package cn.iotnova.opus.utils;

import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import androidx.annotation.NonNull;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import cn.iotnova.rtc.Rtcclient;

public final class OpusRecorderTask implements Runnable {
    int BUFFER_LENGTH = 80;
    private boolean isCancel = false;
    String decodeOpusFilePath = null;
    //public static int DEFAULT_AUDIO_SAMPLE_RATE = 16000;
    //public static int DEFAULT_AUDIO_SAMPLE_RATE = 44100;
    public static int DEFAULT_AUDIO_SAMPLE_RATE = 44100;
    //static int DEFAULT_AUDIO_SAMPLE_RATE = 8000;
    //static int DEFAULT_AUDIO_SAMPLE_RATE = 44100;
    //static int DEFAULT_AUDIO_SAMPLE_RATE = 48000;
    //int DEFAULT_OPUS_CHANNEL = 1; //默认采用单声道
    public static int DEFAULT_OPUS_CHANNEL = 1; //默认采用单声道
    public static int OPUS_COMPLEXITY = 3;    //0-10

    //Rtcclient rtcclient = new Rtcclient();

    Rtcclient rtcclient;
    public OpusRecorderTask(Rtcclient _client) {
        rtcclient = _client;
    }

    private AudioRecord audioRecord;
    private boolean isRecorder;
    //private byte[] audioBuffer;
    private short[] audioBuffer;
    private String opusAudioOpusPath = "";
    private String opusAudioPcmPath = "";
    public static int channelConfig = AudioFormat.CHANNEL_IN_MONO;   //AudioFormat.CHANNEL_IN_FRONT;    //16;
    //public static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;   //AudioFormat.CHANNEL_IN_FRONT;    //16;
    private static int bufferSize;
    public final void stop() {
        this.isRecorder = false;
    }

    @SuppressLint("NewApi")
    public void run() {
        isRecorder = true;
        audioRecord.startRecording();
        File file = new File(opusAudioOpusPath);
        File filePcm = new File(opusAudioPcmPath);
        File fileDir = new File(file.getParent());
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }

        if (file.exists()) {
            file.delete();
        }

        if (filePcm.exists()) {
            filePcm.delete();
        }
        BufferedOutputStream fileOpusBufferedOutputStream = null;
        BufferedOutputStream filePcmBufferedOutputStream = null;
        long createEncoder = 0;
        try {
            file.createNewFile();
            filePcm.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file, true);
            FileOutputStream filePcmOutputStream = new FileOutputStream(filePcm, true);
            fileOpusBufferedOutputStream = new BufferedOutputStream((OutputStream)fileOutputStream);
            filePcmBufferedOutputStream = new BufferedOutputStream((OutputStream)filePcmOutputStream);
            //OpusUtils opusUtils = new OpusUtils();
            //createEncoder = opusUtils.createEncoder(DEFAULT_AUDIO_SAMPLE_RATE, DEFAULT_OPUS_CHANNEL, 3);

            //https://blog.csdn.net/yueliang0423/article/details/103511566
            //https://my.oschina.net/u/4351449/blog/4325762
            createEncoder = OpusUtils.createEncoder(DEFAULT_AUDIO_SAMPLE_RATE, DEFAULT_OPUS_CHANNEL, OPUS_COMPLEXITY);

            while(isRecorder) {
                //System.out.println("opus...");
                int curShortSize = audioRecord.read(audioBuffer, 0, bufferSize);
                if (curShortSize > 0 && curShortSize <= audioBuffer.length) {
                    //filePcmBufferedOutputStream.write(audioBuffer);
                    //byte[] byteArray = new byte[this.audioBuffer.length / 8];
                    //byte[] byteArray = new byte[this.audioBuffer.length / 8];
                    byte[] byteArray = new byte[audioBuffer.length];
                    short[] audioBuf = new short[curShortSize];
                    System.arraycopy(audioBuffer, 0, audioBuf, 0, curShortSize);
                    //int encodeSize = OpusUtils.encode(createEncoder, Uilts.getInstance().byteArrayToShortArray(audioBuffer), 0, byteArray);
                    int encodeSize = OpusUtils.encode(createEncoder, audioBuf, 0, byteArray);
                    if (encodeSize > 0) {
                        byte[] decodeArray = new byte[encodeSize];
                        System.arraycopy(byteArray, 0, decodeArray, 0, encodeSize);
                        //fileOpusBufferedOutputStream.write(decodeArray);

                        rtcclient.SendOpusData(decodeArray, decodeArray.length);
                        System.out.println("opus...");
                    }
                    /*else {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                     */
                }
            }

            OpusUtils.destroyEncoder(createEncoder);
            audioRecord.stop();
            audioRecord.release();
            filePcmBufferedOutputStream.close();
            filePcmOutputStream.close();
            fileOpusBufferedOutputStream.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public OpusRecorderTask(@NonNull String _opusAudioOpusPath, @NonNull String _opusAudioPcmPath, Rtcclient _client) {
        bufferSize = AudioRecord.getMinBufferSize(DEFAULT_AUDIO_SAMPLE_RATE, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
        opusAudioOpusPath = _opusAudioOpusPath;
        opusAudioPcmPath = _opusAudioPcmPath;
        rtcclient = _client;
        //audioBuffer = new byte[640];
        audioBuffer = new short[bufferSize];
        //audioBuffer = new short[640];
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, DEFAULT_AUDIO_SAMPLE_RATE, channelConfig, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
    }
}
